#include <fsmc/FSMC.h>
#include <rtdevice.h>
#include <threadunit/SDRAMDEF.h>

#define fifo_full 66
#define write_date(offset, data) *((volatile unsigned short int *)(0x60000000 + (offset << 1))) = data
#define read_date(offset) *((volatile unsigned short int *)(0x60000000 + (offset << 1)))

static unsigned int sramLock = 0;
rt_mailbox_t polaris_data_mail = RT_NULL;
static unsigned state = 0;

void full_iqr(void *args)
{
    sramLock = 1;
}

/**
 * @brief sram entry thread, Used for processing SRAM data transmission, receiving data through mailbox, and performing reset or data read operations based on the state
 * (用于处理SRAM的数据传输，通过邮箱接收数据，并根据状态进行复位或数据读取的操作)
 * @param parameter unused
 */
void sram_entry(void *parameter)
{
    rt_ubase_t *r_str;
    while (1)
    {
        switch (state)
        {
        case 0: // 复位
            while (polaris_data_mail->entry != 0)
                rt_mb_recv(polaris_data_mail, (rt_ubase_t *)(&r_str), RT_WAITING_FOREVER);
            state++;
            break;
        case 1:
            rt_mb_recv(polaris_data_mail, (rt_ubase_t *)(&r_str), RT_WAITING_FOREVER);
            for (unsigned int i = 0; i < (*r_str); i++)
            {
                while (sramLock)
                {
                    rt_thread_mdelay(1);
                    if (rt_pin_read(fifo_full) == 0)
                        sramLock = 0;
                    if (state == 0)
                        break;
                }
                if (state == 0)
                    break;
                write_date(500, i);
            }
            break;
        default:
            break;
        }
    }
}

FSMC::FSMC()
{
    init();
}

FSMC::~FSMC()
{
    // TODO 自动生成的析构函数存根
}

/**
 * @brief initialize FSMC, setting pin and create mailbox and thread
 * （初始化FSMC，设置引脚属性以及创建邮箱和线程）
 */
void FSMC::init()
{
    rt_pin_mode(fifo_full, PIN_MODE_INPUT_PULLUP);
    rt_pin_attach_irq(fifo_full, PIN_IRQ_MODE_RISING, full_iqr, RT_NULL);
    rt_pin_irq_enable(fifo_full, PIN_IRQ_ENABLE);

    polaris_data_mail = rt_mb_create("polaris_data_mail", 10, RT_IPC_FLAG_FIFO);

    rt_thread_t tid1 = RT_NULL;
    tid1 = rt_thread_create("SRAM", sram_entry, NULL, 2048, 1, 10);
    if (tid1 != RT_NULL)
    {
        rt_thread_startup(tid1);
    }
}

void FSMC::readFsmc(unsigned int add, unsigned short int *num)
{
    *num = read_date(add);
}

void FSMC::writeFsmc(unsigned int add, unsigned short int num)
{
    write_date(add, num);
}

void FSMC::writeReg(unsigned int addr, unsigned int bit, unsigned int flag)
{
    unsigned int state = 0;
    state = read_date(addr);
    if (flag == 0)
    {
        write_date(addr, state & (~(0x0001 << bit)));
    }
    else
    {
        write_date(addr, state | 0x0001 << bit);
    }
}

void FSMC::resetSram()
{
    // 复位sram线程和邮箱信号
    state = 0;
    rt_thread_mdelay(10);
    // 复位fpga内部数据
    writeReg(501, 1, 1);
    rt_thread_mdelay(1);
    writeReg(501, 1, 0);
}

void FSMC::transData2Fsmc(rt_ubase_t num, uint32_t startAddr)
{
    state = 1;
    for (unsigned int i = 0; i < num / 2; i++)
    {
        while (sramLock)
        {
            rt_thread_mdelay(1);
            if (rt_pin_read(fifo_full) == 0)
                sramLock = 0;
            if (state == 0)
                break;
        }
        if (state == 0)
            break;
        uint32_t addr = (startAddr - 0xC0800000 + i);
        unsigned short int data = read_sdram(addr);
        //        rt_kprintf("id:%d startAddr :%x,write_date :%x\r\n",i,addr,data);
        write_date(500, data);
    }
}
